<template>
  <view
    :id="foldId"
    class="mxp-fold"
    :style="[
      {
        backgroundColor: background,
        height: contentHeightNumb > heightNumb ? contentHeight : `${contentHeightNumb}px`,
        transitionDuration: contentHeightNumb > heightNumb ? duration + 'ms' : 0 + 'ms',
      },
      cusStyle,
    ]"
    :class="[cusClass]"
  >
    <view :id="foldContentViewId" class="fold-content-view" :style="[contentViewStyle]">
      <slot>
        <text :style="[newContentStyle]">{{ content }}</text>
      </slot>
    </view>
    <template v-if="contentHeightNumb > heightNumb">
      <view
        v-if="buttonPosition === 'bottom'"
        class="bottom-button-view"
        :style="[{ position: isFold ? 'absolute' : 'relative' }]"
        @click.stop.prevent="changeFoldClick"
      >
        <view v-if="isFold" class="flex-view" :style="[bottomShadowStyle]"></view>
        <view class="flex-view" :style="{ backgroundColor: background, height: newButtonHeight }">
          <slot name="button">
            <text class="text" :style="{ fontSize: buttonSize, color: buttonColor }">{{ isFold ? foldText : unfoldText }}</text>
            <mxp-icon v-if="showIcon" name="xiajiantou" :size="buttonSize" :color="buttonColor" :cusStyle="newIconStyle"></mxp-icon>
          </slot>
        </view>
      </view>
      <view
        v-if="buttonPosition === 'right'"
        key="view-2"
        class="left-button-view"
        :style="[{ position: isFold ? 'absolute' : 'relative', justifyContent: isFold ? 'flex-end' : 'center' }]"
        @click.stop.prevent="changeFoldClick"
      >
        <view v-if="isFold" class="left-shadow-view" :style="[bottomShadowStyle, { height: newButtonHeight }]"></view>
        <view class="left-button" :style="{ backgroundColor: background, height: newButtonHeight }">
          <slot name="button">
            <text :style="{ fontSize: buttonSize, color: buttonColor, lineHeight: props.contentLineHeight }">
              {{ isFold ? foldText : unfoldText }}
            </text>
            <mxp-icon v-if="showIcon" name="youjiantou" :size="buttonSize" :color="buttonColor" :cusStyle="newIconStyle"></mxp-icon>
          </slot>
        </view>
      </view>
    </template>
  </view>
</template>

<script lang="ts" setup>
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import { type CSSProperties, type PropType, computed, getCurrentInstance, onMounted, ref, watch } from 'vue';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import MxpIcon from '../mxp-icon/mxp-icon.vue';
  import { getDomSize, getXPNumber } from '../mxp-tool/utils/dom';
  import { getOnlyID } from '../mxp-tool/utils/common';
  defineOptions({
    name: 'mxp-fold',
  });

  const props = defineProps({
    /** 是否显示icon */
    showIcon: { type: Boolean, default: true },
    /** 是否折叠 */
    modelValue: { type: Boolean, default: true },
    /** 折叠动画的时间(单位：毫秒) */
    duration: { type: Number, default: 300 },
    /** 可见高度,建议 (当buttonPosition==='right' 时建议 可见高度(contentLineHeight)为行高的倍数)  */
    height: { type: String as PropType<$SizeUnitStr>, default: '168px' },
    /** 背景颜色 */
    background: { type: String as PropType<$AllColorStr>, default: '#ffffff' },
    /** 按钮位置 */
    buttonPosition: { type: String as PropType<'bottom' | 'right'>, default: 'bottom' },
    /** 折叠的提示文本 */
    foldText: { type: String, default: '查看更多' },
    /** 展开的提示文本 */
    unfoldText: { type: String, default: '收起内容' },
    /** 内容 */
    content: { type: [Number, String], default: '' },
    /** 内容的字体大小 */
    contentSize: { type: String as PropType<$SizeUnitStr>, default: '14px' },
    /** 内容的颜色 */
    contentColor: { type: String as PropType<$AllColorStr>, default: '#666666' },
    /** 内容的样式 */
    contentStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 文本的行高 (当buttonPosition==='right' 时建议 可见高度(height)为行高的倍数) */
    contentLineHeight: { type: String as PropType<$SizeUnitStr>, default: undefined },
    /** 按钮的字体大小 */
    buttonSize: { type: String as PropType<$SizeUnitStr>, default: '14px' },
    /** 按钮的颜色 */
    buttonColor: { type: String as PropType<$AllColorStr>, default: '#223aec' },
    /** 阴影部分的长度 */
    shadowLength: { type: String as PropType<$AllColorStr>, default: '40px' },
    /** 收起/折叠 按钮的高度 */
    buttonHeight: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 内容容器的样式 */
    contentViewStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 主体内容 */
    default?: () => void;
    /** 底部 */
    button?: () => void;
  }>();

  const emits = defineEmits<{
    (e: 'change', isFold: boolean): void;
    (e: 'update:modelValue', isFold: boolean): void;
  }>();
  const newButtonHeight = computed(() => props.buttonHeight || props.contentLineHeight || '24px');
  const newContentLineHeight = computed(() => props.contentLineHeight || props.buttonHeight || '24px');

  /** 是否展开 */
  const isFold = ref(props.modelValue);
  /** 内容高度 (nvue不支持 auto) */
  const contentHeight = ref<$SizeUnitStr>(props.height);
  /** 内容宽度(nvue不支持  100%) */
  const instance = getCurrentInstance();
  const foldId = getOnlyID('mxp-fold');
  const foldContentViewId = getOnlyID('mxp-fold-content-view');
  const contentHeightNumb = ref(0);
  watch(
    () => props.modelValue,
    (state) => {
      isFold.value = state;
      setContentHeight();
    },
    { immediate: true }
  );

  watch(
    () => props.content,
    () => {
      getContentViewHeight().then((res) => {
        contentHeightNumb.value = res || 0;
      });
    },
    { immediate: true }
  );
  onMounted(() => {
    setTimeout(() => {
      getContentViewHeight().then((res) => {
        contentHeightNumb.value = res || 0;
      });
    }, 10);
  });

  const heightNumb = computed(() => getXPNumber(props.height));

  /** 内容文文本的最终本的样式 */
  const newContentStyle = computed<CSSProperties>(() => ({
    fontSize: props.contentSize,
    color: props.contentColor,
    lineHeight: newContentLineHeight.value,
    ...props.contentStyle,
  }));
  /** 底部按钮阴影的样式 */
  const bottomShadowStyle = computed<CSSProperties>(() => ({
    height: props.shadowLength,
    backgroundImage: `linear-gradient(to ${props.buttonPosition},rgba(255,255,255,0), ${props.background})`,
  }));

  /** icon 最终的样式 */
  const newIconStyle = computed<CSSProperties>(() => ({
    transitionProperty: 'transform',
    transitionDuration: '0.2s',
    transform: `rotate(${isFold.value ? 0 : props.buttonPosition === 'bottom' ? -180 : -90}deg)`,
  }));

  /**
   * 点击展开或者折叠
   */
  function changeFoldClick() {
    isFold.value = !isFold.value;
    setContentHeight();
  }
  /** 设置高度 */
  async function setContentHeight() {
    if (isFold.value) {
      contentHeight.value = props.height;
    } else {
      // 注意当父元素为 flex布局时 一定要给子元素添加 flex-shrink: 0; 否则折叠不能正确获取到子元素的高度
      const height = await getContentViewHeight();
      if (props.buttonPosition === 'bottom') {
        contentHeight.value = `${height! + parseInt(props.shadowLength) + parseInt(newButtonHeight.value)}px`;
      } else {
        contentHeight.value = `${height! + parseInt(newButtonHeight.value)}px`;
      }
    }
    emits('change', isFold.value);
    emits('update:modelValue', isFold.value);
  }

  /** 得到内容的高度 */
  async function getContentViewHeight() {
    // 注意当父元素为 flex布局时 一定要给子元素添加 flex-shrink: 0; 否则折叠不能正确获取到子元素的高度
    const size = await getDomSize(`#${foldContentViewId}`, instance);
    return Promise.resolve(size.height);
  }
</script>

<style lang="scss" scoped>
  .mxp-fold {
    position: relative;
    display: flex;
    flex-flow: column nowrap;
    align-items: flex-start;
    justify-content: flex-start;
    overflow: hidden;
    transition-timing-function: ease;
    transition-duration: 0.3s;
    transition-property: height;

    .fold-content-view {
      overflow: hidden;
    }
    // #ifndef APP-NVUE
    // stylelint-disable-next-line no-duplicate-selectors
    .fold-content-view {
      // 注意当父元素为 flex一定要给子元素添加 flex-shrink: 0; 否则折叠不能正确获取到子元素的高度
      flex-shrink: 0;
    }
    // #endif

    .bottom-button-view {
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 2;
      display: flex;
      flex: 1;
      flex-flow: column nowrap;
      align-items: stretch;
      width: 100%;
      overflow: hidden;

      .flex-view {
        display: flex;
        flex-flow: row nowrap;
        align-items: center;
        justify-content: center;
      }
    }

    .left-button-view {
      right: 0;
      bottom: 0;
      left: 0;
      display: flex;
      flex-flow: row nowrap;
      align-items: center;
      justify-content: flex-end;
      width: 100%;
      overflow: hidden;

      .left-shadow-view {
        width: 40px;
      }

      .left-button {
        display: flex;
        flex-flow: row nowrap;
        align-items: center;
        justify-content: center;
        padding: 0 10px;
      }
    }
  }
</style>
